//index.js
//获取应用实例
const app = getApp()
function inArray(arr, key, val) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i][key] === val) {
      return i;
    }
  }
  return -1;
}

// ArrayBuffer转16进度字符串示例
function ab2hex(buffer) {
  var hexArr = Array.prototype.map.call(
    new Uint8Array(buffer),
    function (bit) {
      return ('00' + bit.toString(16)).slice(-2)
    }
  )
  return hexArr.join('');
}
Page({
  data: {
    device: null,
    connected: false,
    devices: [],
    deviceId: "E6:A8:C1:ED:B0:04",
    chs: []
  },
  onLoad: function () {},
  // 初始化蓝牙模块
  openBluetoothAdapter() {
    // 其他蓝牙相关 API 必须在 wx.openBluetoothAdapter 调用之后使用。否则 API 会返回错误（errCode=10000）
    wx.openBluetoothAdapter({
      success: (res) => {
        console.log('openBluetoothAdapter success', res)
        this.startBluetoothDevicesDiscovery()
      },
      fail: (res) => {
        /* 在用户蓝牙开关未开启或者手机不支持蓝牙功能的情况下，调用 wx.openBluetoothAdapter 会返回错误（errCode=10001）表示手机蓝牙功能不可用。 此时小程序蓝牙模块已经初始化完成，可通过 wx.onBluetoothAdapterStateChange 监听手机蓝牙状态的改变，也可以调用蓝牙模块的所有API */
        if (res.errCode === 10001) {
          wx.showToast({
            title:'蓝牙开启失败,请检查手机蓝牙是否已打开',
            icon:'none',
            duration:2000
          })
          wx.onBluetoothAdapterStateChange((res) => {
            console.log('onBluetoothAdapterStateChange', res)
            if (res.available) {
              this.startBluetoothDevicesDiscovery()
            }
          })
        }
      }
    })
  },
  // 获取本机蓝牙适配器状态
  getBluetoothAdapterState() {
    wx.getBluetoothAdapterState({
      success: (res) => {
        console.log('getBluetoothAdapterState', res)
        if (res.discovering) {
          this.onBluetoothDeviceFound()
        } else if (res.available) {
          this.startBluetoothDevicesDiscovery()
        }
      }
    })
  },
  startBluetoothDevicesDiscovery() {
    if (this._discoveryStarted) {
      return
    }
    wx.showLoading({
      title: '设备搜索中...'
    })
    this._discoveryStarted = true
    wx.startBluetoothDevicesDiscovery({
      allowDuplicatesKey: true,
      success: (res) => {
        console.log('startBluetoothDevicesDiscovery success', res)
        this.onBluetoothDeviceFound()
      },
    })
  },
  // 停止搜寻附近的蓝牙外围设备。若已经找到需要的蓝牙设备并不需要继续搜索时，建议调用该接口停止蓝牙搜索
  stopBluetoothDevicesDiscovery() {
    wx.offBLEConnectionStateChange()
    wx.stopBluetoothDevicesDiscovery()
  },
  // 监听寻找到新设备的事件
  onBluetoothDeviceFound() {
    // 若在 wx.onBluetoothDeviceFound 回调了某个设备，则此设备会添加到 wx.getBluetoothDevices 接口获取到的数组中
    wx.onBluetoothDeviceFound((res) => {
      res.devices.forEach(device => {
        console.log(device.name, device.localName)
        if (!device.name && !device.localName) {
          return
        }
        // 连接指定的设备
        if (device.deviceId == this.data.deviceId) {
          this.stopBluetoothDevicesDiscovery()
          wx.hideLoading()
          this.setData({
            device: device
          })
          this.createBLEConnection(device.deviceId)
        }
      })
    })
  },
  // 连接低功耗蓝牙设备
  createBLEConnection(deviceId) {
    console.log('正在尝试连接设备...')
    wx.showLoading({
      title: '设备连接中...'
    })
    // 取消监听低功耗蓝牙连接状态的改变事件
    wx.offBLEConnectionStateChange()
    // 若小程序在之前已有搜索过某个蓝牙设备，并成功建立连接，可直接传入之前搜索获取的 deviceId 直接尝试连接该设备，无需进行搜索操作
    wx.createBLEConnection({
      deviceId,
      success: (res) => {
        wx.hideLoading()
        this.setData({
          connected: true
        })
        this.getBLEDeviceServices(deviceId)
        this.watchBLEConnectionState()
      }
    })
  },
  // 断开与低功耗蓝牙设备的连接
  closeBLEConnection() {
    wx.closeBLEConnection({
      deviceId: this.data.deviceId
    })
    this.setData({
      connected: false,
      chs: [],
      canWrite: false,
    })
  },
  // 重连蓝牙设备
  reconnectionBLEDevices () {
    this.createBLEConnection(this.data.deviceId)
  },
  // 获取蓝牙设备所有服务
  getBLEDeviceServices(deviceId) {
    wx.getBLEDeviceServices({
      deviceId,
      success: (res) => {
        for (let i = 0; i < res.services.length; i++) {
          if (res.services[i].isPrimary) {
            this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
            return
          }
        }
      }
    })
  },
  // 获取蓝牙设备某个服务中所有特征值
  getBLEDeviceCharacteristics(deviceId, serviceId) {
    wx.getBLEDeviceCharacteristics({
      deviceId,
      serviceId,
      success: (res) => {
        console.log('getBLEDeviceCharacteristics success', res.characteristics)
        for (let i = 0; i < res.characteristics.length; i++) {
          let item = res.characteristics[i]
          if (item.properties.read) {
            wx.readBLECharacteristicValue({
              deviceId,
              serviceId,
              characteristicId: item.uuid,
              success: res => {
                console.log(res)
              }
            })
          }
          if (item.properties.write) {
            this.setData({
              canWrite: true
            })
            this._deviceId = deviceId
            this._serviceId = serviceId
            this._characteristicId = item.uuid
            this.writeBLECharacteristicValue()
          }
          if (item.properties.notify || item.properties.indicate) {
            wx.notifyBLECharacteristicValueChange({
              deviceId,
              serviceId,
              characteristicId: item.uuid,
              state: true,
            })
          }
        }
      },
      fail(res) {
        console.error('getBLEDeviceCharacteristics', res)
      }
    })
    // 操作之前先监听，保证第一时间获取数据
    wx.onBLECharacteristicValueChange((characteristic) => {
      const idx = inArray(this.data.chs, 'uuid', characteristic.characteristicId)
      const data = {}
      if (idx === -1) {
        data[`chs[${this.data.chs.length}]`] = {
          uuid: characteristic.characteristicId,
          value: ab2hex(characteristic.value)
        }
      } else {
        data[`chs[${idx}]`] = {
          uuid: characteristic.characteristicId,
          value: ab2hex(characteristic.value)
        }
      }
      this.setData(data)
    })
  },
  writeBLECharacteristicValue() {
    // 向蓝牙设备发送一个0x00的16进制数据
    let buffer = new ArrayBuffer(1)
    let dataView = new DataView(buffer)
    dataView.setUint8(0, Math.random() * 255 | 0)
    wx.writeBLECharacteristicValue({
      deviceId: this._deviceId,
      serviceId: this._deviceId,
      characteristicId: this._characteristicId,
      value: buffer,
    })
  },
  // 关闭蓝牙模块。调用该方法将断开所有已建立的连接并释放系统资源。建议在使用蓝牙流程后，与 wx.openBluetoothAdapter 成对调用
  closeBluetoothAdapter() {
    wx.offBLEConnectionStateChange()
    wx.closeBluetoothAdapter()
    this._discoveryStarted = false
  },
  // 监听低功耗蓝牙连接状态的改变事件。包括开发者主动连接或断开连接，设备丢失，连接异常断开等等
  watchBLEConnectionState () {
    var _this = this
    wx.onBLEConnectionStateChange(function(res) {
      // 该方法回调中可以用于处理连接意外断开等异常情况
      console.log(`设备 ${res.deviceId} 状态已改变, 是否连接: ${res.connected}`)
      if (res.connected) {
        wx.showToast({
          title: '蓝牙设备已连接',
          icon: 'success'
        })
      } else {
        wx.showModal({
          title: '蓝牙',
          content: '连接已断开，是否重连',
          success: res => {
            if (res.confirm) {
              _this.createBLEConnection(_this.data.deviceId)
            }
          }
        })
      }
    })
  }
})
